package com.xzy.mybatis.cipher.support.strategy.parse;

import com.alibaba.druid.sql.ast.SQLExpr;
import com.alibaba.druid.sql.ast.SQLStatement;
import com.alibaba.druid.sql.ast.expr.*;
import com.alibaba.druid.sql.ast.statement.*;
import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlSelectQueryBlock;
import com.alibaba.druid.sql.parser.ParserException;
import com.xzy.mybatis.cipher.support.registry.CryptoMetadataRegistry;
import com.xzy.mybatis.cipher.support.registry.DataCryptoStrategyRegistry;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * @author xzy.xiao
 * @since 2025/1/14  16:31
 */
public abstract class ParseStrategy {

    protected CryptoMetadataRegistry cryptoMetadataRegistry;
    protected DataCryptoStrategyRegistry dataCryptoStrategyRegistry;

    public ParseStrategy(CryptoMetadataRegistry cryptoMetadataRegistry, DataCryptoStrategyRegistry dataCryptoStrategyRegistry) {
        this.cryptoMetadataRegistry = cryptoMetadataRegistry;
        this.dataCryptoStrategyRegistry = dataCryptoStrategyRegistry;
    }

    public abstract List<Object> parse(String datasourceName, SQLStatement sqlStatement, List<Object> originalPropertyValueList);

    protected final List<String> extractedQuery(SQLSelectQuery query, Map<String, String> aliasTableMap) {
        List<String> whereColumnList = new ArrayList<>();
        extractedQuery(query, aliasTableMap, whereColumnList);
        return whereColumnList;
    }

    protected final List<String> extractedWhere(SQLExpr where, Map<String, String> aliasTableMap) {
        List<String> whereColumnList = new ArrayList<>();
        extractedWhere(where, aliasTableMap, whereColumnList);
        return whereColumnList;
    }

    // SUPPORT
    private void extractedWhere(SQLExpr where, Map<String, String> aliasTableMap, List<String> whereColumnList) {
        if (where instanceof SQLBinaryOpExpr) {
            SQLBinaryOpExpr sqlBinaryWhere = (SQLBinaryOpExpr) where;
            if (sqlBinaryWhere.getLeft() instanceof SQLPropertyExpr
                    || sqlBinaryWhere.getLeft() instanceof SQLIdentifierExpr) {
                // 占位符才处理
                if (sqlBinaryWhere.getRight() instanceof SQLVariantRefExpr) {
                    whereColumnList.add(sqlBinaryWhere.getLeft().toString());
                }
            } else {
                extractedWhere(sqlBinaryWhere.getLeft(), aliasTableMap, whereColumnList);
                extractedWhere(sqlBinaryWhere.getRight(), aliasTableMap, whereColumnList);
            }
        } else if (where instanceof SQLInListExpr) {
            SQLInListExpr expr = (SQLInListExpr) where;
            SQLExpr innerExpr = expr.getExpr();
            // 单列in
            if (innerExpr instanceof SQLPropertyExpr) {
                for (int i = 0; i < expr.getTargetList().size(); i++) {
                    // 占位符才处理
                    if (expr.getTargetList().get(i) instanceof SQLVariantRefExpr) {
                        whereColumnList.add(expr.getExpr().toString());
                    }
                }
            } else if (innerExpr instanceof SQLListExpr) {
                // 多列in
                List<SQLExpr> columns = ((SQLListExpr) innerExpr).getItems();
                for (SQLExpr sqlExpr : expr.getTargetList()) {
                    SQLListExpr sqlListExpr = (SQLListExpr) sqlExpr;
                    for (int i = 0; i < columns.size(); i++) {
                        // 占位符才处理
                        if (sqlListExpr.getItems().get(i) instanceof SQLVariantRefExpr) {
                            whereColumnList.add(columns.get(i).toString());
                        }
                    }
                }
            }
        } else if (where instanceof SQLBetweenExpr) {
            SQLBetweenExpr expr = (SQLBetweenExpr) where;
            // 占位符才处理
            if (expr.getBeginExpr() instanceof SQLVariantRefExpr) {
                whereColumnList.add(expr.getTestExpr().toString());
            }
            // 占位符才处理
            if (expr.getEndExpr() instanceof SQLVariantRefExpr) {
                whereColumnList.add(expr.getTestExpr().toString());
            }
        } else if (where instanceof SQLInSubQueryExpr) {
            SQLInSubQueryExpr sqlInSubQueryExpr = (SQLInSubQueryExpr) where;
            extractedQuery(sqlInSubQueryExpr.getSubQuery().getQuery(), aliasTableMap, whereColumnList);
        }
    }

    private void extractedQuery(SQLSelectQuery query, Map<String, String> aliasTableMap, List<String> whereColumnList) {
        if (query instanceof SQLUnionQuery) {
            SQLUnionQuery unionQuery = (SQLUnionQuery) query;
            SQLSelectQuery left = unionQuery.getLeft();
            extractedQuery(left, aliasTableMap, whereColumnList);
            SQLSelectQuery right = unionQuery.getRight();
            extractedQuery(right, aliasTableMap, whereColumnList);
        } else if (query instanceof MySqlSelectQueryBlock) {
            MySqlSelectQueryBlock queryBlock = (MySqlSelectQueryBlock) query;
            SQLTableSource from = queryBlock.getFrom();
            extractedFrom(from, aliasTableMap, whereColumnList);
            extractedWhere(queryBlock.getWhere(), aliasTableMap, whereColumnList);
        } else {
            throw new ParserException("暂不支持" + query.getClass() + "!");
        }
    }

    private void extractedFrom(SQLTableSource sqlTableSource, Map<String, String> aliasTableMap, List<String> whereColumnList) {
        // 单表查询
        if (sqlTableSource instanceof SQLExprTableSource) {
            SQLExprTableSource exprTableSource = (SQLExprTableSource) sqlTableSource;
            SQLExpr expr = exprTableSource.getExpr();
            String tableName = expr.toString();
            String tableAliasName = exprTableSource.getAlias();
            aliasTableMap.put(tableAliasName, tableName);
        } else if (sqlTableSource instanceof SQLJoinTableSource) {
            // 联表查询
            SQLJoinTableSource joinTableSource = (SQLJoinTableSource) sqlTableSource;
            SQLTableSource left = joinTableSource.getLeft();
            extractedFrom(left, aliasTableMap, whereColumnList);
            SQLTableSource right = joinTableSource.getRight();
            extractedFrom(right, aliasTableMap, whereColumnList);
        } else if (sqlTableSource instanceof SQLUnionQueryTableSource) {
            // 联合查询
            SQLUnionQueryTableSource unionQueryTableSource = (SQLUnionQueryTableSource) sqlTableSource;
            SQLUnionQuery union = unionQueryTableSource.getUnion();
            extractedQuery(union, aliasTableMap, whereColumnList);
        } else if (sqlTableSource instanceof SQLSubqueryTableSource) {
            // 子查询
            SQLSubqueryTableSource subQueryTableSource = (SQLSubqueryTableSource) sqlTableSource;
            SQLSelect select = subQueryTableSource.getSelect();
            extractedQuery(select.getQuery(), aliasTableMap, whereColumnList);
        } else {
            throw new ParserException("暂不支持" + sqlTableSource.getClass() + "!");
        }
    }

}
